package monitor

import (
	"fmt"
	"io/ioutil"
	"strconv"
	"strings"
)

var netDevFilePath = "/proc/net/dev"

type NetMonitor struct {
	hasBeenSetBeginBytes bool
	BeginReceiveBytes    map[string]string
	EndReceiveBytes      map[string]string
	BeginSendBytes       map[string]string
	EndSendBytes         map[string]string
}

//noinspection GoUnusedExportedFunction
func NewNetMonitor() *NetMonitor {
	return &NetMonitor{hasBeenSetBeginBytes: false, BeginReceiveBytes: make(map[string]string), EndReceiveBytes: make(map[string]string), BeginSendBytes: make(map[string]string), EndSendBytes: make(map[string]string)}
}

//noinspection GoUnusedGlobalVariable
var avgDownload int64

//noinspection GoUnusedExportedFunction
func CalcNetworkSendUsage(monitor *NetMonitor, seconds int64) map[string]float64 {
	resultMap := make(map[string]float64)

	for ek, ev := range monitor.EndSendBytes {
		for bk, bv := range monitor.BeginSendBytes {
			if ek == bk {
				evi, _ := strconv.ParseInt(ev, 10, 64)
				bvi, _ := strconv.ParseInt(bv, 10, 64)
				resultMap[ek] = float64(evi-bvi) / float64(seconds) / 1024 / 1024
			}
		}
	}
	return resultMap
}

//noinspection GoUnusedExportedFunction
func CalcNetworkReceiveUsage(monitor *NetMonitor, seconds int64) map[string]float64 {
	resultMap := make(map[string]float64)

	for ek, ev := range monitor.EndReceiveBytes {
		for bk, bv := range monitor.BeginReceiveBytes {
			if ek == bk {
				evi, _ := strconv.ParseInt(ev, 10, 64)
				bvi, _ := strconv.ParseInt(bv, 10, 64)
				resultMap[ek] = float64(evi-bvi) / float64(seconds) / 1024 / 1024
			}
		}
	}
	return resultMap
}

//noinspection GoUnusedExportedFunction
func FetchNetworkInfo(monitor *NetMonitor) {
	bytes, e := ioutil.ReadFile(netDevFilePath)
	if e != nil {
		fmt.Println(e)
		return
	}
	s := string(bytes)
	split := strings.Split(s, "\n")
	parseReceiveBytes(split, monitor)
	parseSendBytes(split, monitor)
	monitor.hasBeenSetBeginBytes = true
}

func parseSendBytes(split []string, monitor *NetMonitor) {
	for k, v := range split {
		if k < 2 {
			continue
		}
		line := clearCharacter(v, " ")
		line = strings.Replace(line, ":", "", len(line))
		lineSplit := strings.Split(line, ",")
		if len(lineSplit) > 9 {
			if monitor.hasBeenSetBeginBytes {
				monitor.EndSendBytes[lineSplit[0]] = lineSplit[9]
			} else {
				monitor.BeginSendBytes[lineSplit[0]] = lineSplit[9]
			}
		}
	}
}

func parseReceiveBytes(split []string, monitor *NetMonitor) {
	for k, v := range split {
		if k < 2 {
			continue
		}
		line := clearCharacter(v, " ")
		line = strings.Replace(line, ":", "", len(line))
		lineSplit := strings.Split(line, ",")
		if len(lineSplit) > 9 {
			if monitor.hasBeenSetBeginBytes {
				monitor.EndReceiveBytes[lineSplit[0]] = lineSplit[1]
			} else {
				monitor.BeginReceiveBytes[lineSplit[0]] = lineSplit[1]
			}
		}
	}
}

func clearCharacter(str string, subStr string) string {
	chars := subStr

	if strings.Contains(str, chars) {
		str = clearCharacter(str, chars+" ")
	}
	replace := strings.Replace(str, chars, ",", len(str))
	for strings.HasPrefix(replace, ",") {
		ru := []rune(replace)
		replace = string(ru[1:len(replace)])
	}
	for strings.HasSuffix(replace, ",") {
		ru := []rune(replace)
		replace = string(ru[len(replace)-2 : len(replace)-1])
	}
	return replace

}
